package com.github.mzule.abilityrouter.router;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.IntentParams;
import ohos.utils.net.Uri;
import java.util.Set;
/**
 * Created by CaoDongping on 4/6/16.
 */
public class Mapping {
    private final String format;
    private final Class<? extends Ability> abilitys;
    private final MethodInvoker method;
    private final ExtraTypes extraTypes;
    private Path formatPath;
    /**
     * 映射
     *
     *  @param  format 格式
     *  @param  ability 目标ability类
     *  @param  method 方法调用者
     *  @param  extraTypes 额外类型
     */
    public Mapping(String format, Class<? extends Ability> ability, MethodInvoker method, ExtraTypes extraTypes) {
        if (format == null) {
            throw new NullPointerException("format can not be null");
        }
        this.format = format;
        this.abilitys = ability;
        this.method = method;
        this.extraTypes = extraTypes;
        if (format.toLowerCase().startsWith("http://") || format.toLowerCase().startsWith("https://")) {
            this.formatPath = Path.create(Uri.parse(format));
        } else {
            this.formatPath = Path.create(Uri.parse("helper://".concat(format)));
        }
    }

    public MethodInvoker getMethod() {
        return method;
    }

    public Class<? extends Ability> getAbility() {
        return abilitys;
    }

    public String getFormat() {
        return format;
    }

    @Override
    public String toString() {
        return String.format("%s => %s", format, abilitys);
    }

    @Override
    public boolean equals(Object o1) {
        if (this == o1) {
            return true;
        }
        if (o1 instanceof Mapping) {
            Mapping that = (Mapping) o1;
            return format.equals(that.format);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return format.hashCode();
    }
    /**
     * 匹配
     *
     *  @param  fullLink URI链接
     *  @return match 进行匹配
     */
    public boolean match(Path fullLink) {
        if (formatPath.isHttp()) {
            return Path.match(formatPath, fullLink);
        } else {
            // fullLink without host
            boolean match = Path.match(formatPath.next(), fullLink.next());
            if (!match && fullLink.next() != null) {
                // fullLink with host
                match = Path.match(formatPath.next(), fullLink.next().next());
            }
            return match;
        }
    }
    /**
     * 解析附加内容
     *
     *  @param  uri 地址
     *  @return IntentParams 用来存取内容
     */
    public IntentParams parseExtras(Uri uri) {
        IntentParams bundle = new IntentParams();

        // path segments // ignore scheme
        Path pa = formatPath.next();
        Path ya = Path.create(uri).next();

        while (pa != null) {
            if (pa.isArgument()) {
                put(bundle, pa.argument(), ya.value());
            }
            pa = pa.next();
            ya = ya.next();
        }

        // parameter
        Set<String> names = UriCompact.getQueryParameterNames(uri);

        IntentParams intentParams = new IntentParams();
        for (String name : names) {
            String value = uri.getFirstQueryParamByKey(name);
            intentParams.setParam(name,bundle);
            put(bundle, name, value);
        }
        return bundle;
    }

    private void put(IntentParams bundle, String name, String value) {
        int type = extraTypes.getType(name);
        name = extraTypes.transfer(name);
        if (type == ExtraTypes.STRING) {
            type = extraTypes.getType(name);
        }
        switch (type) {
            case ExtraTypes.INT:
                bundle.setParam(name, Integer.parseInt(value));
                break;
            case ExtraTypes.LONG:
                bundle.setParam(name, Long.parseLong(value));
                break;
            case ExtraTypes.BOOL:
                bundle.setParam(name, Boolean.parseBoolean(value));
                break;
            case ExtraTypes.SHORT:
                bundle.setParam(name, Short.parseShort(value));
                break;
            case ExtraTypes.FLOAT:
                bundle.setParam(name, Float.parseFloat(value));
                break;
            case ExtraTypes.DOUBLE:
                bundle.setParam(name, Double.parseDouble(value));
                break;
            case ExtraTypes.BYTE:
                bundle.setParam(name, Byte.parseByte(value));
                break;
            case ExtraTypes.CHAR:
                bundle.setParam(name, value.charAt(0));
                break;
            default:
                bundle.setParam(name, value);
                break;
        }
    }
}
